#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include <QtEndian>
#include "qbytearrayutil.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 正则表达式限制输入16进制
    auto hexValdidator = new QRegularExpressionValidator(QRegularExpression("([A-Fa-f0-9])*"));
    ui->utf8->setValidator(hexValdidator);
    ui->utf32->setValidator(hexValdidator);
    ui->hex->setValidator(hexValdidator);

    auto octValdidator = new QRegularExpressionValidator(QRegularExpression("[0-7]*"));
    ui->oct->setValidator(octValdidator);

    auto binValdidator = new QRegularExpressionValidator(QRegularExpression("[0-1]*"));
    ui->bin->setValidator(binValdidator);

    auto fltValdidator = new QRegularExpressionValidator(QRegularExpression("-?[0-9]*(\.[0-9]*)?(e[+|-]?[0-9]+)?"));
    ui->flt->setValidator(fltValdidator);
    ui->dbl->setValidator(fltValdidator);

    auto unsignedValdidator = new QRegularExpressionValidator(QRegularExpression("[0-9]*"));
    ui->u8->setValidator(unsignedValdidator);
    ui->u16->setValidator(unsignedValdidator);
    ui->u32->setValidator(unsignedValdidator);
    ui->u64->setValidator(unsignedValdidator);

    auto signedValdidator = new QRegularExpressionValidator(QRegularExpression("-?[0-9]*"));
    ui->s8->setValidator(signedValdidator);
    ui->s16->setValidator(signedValdidator);
    ui->s32->setValidator(signedValdidator);
    ui->s64->setValidator(signedValdidator);
}

MainWindow::~MainWindow()
{
    delete ui;
}

namespace kPrivate
{
    bool updating{ false };

    enum KeByteEncoding
    {
        k_bin_changed = 0x0001,
        k_oct_changed = 0x0002,
        k_hex_changed = 0x0004,
        k_flt_changed = 0x0008,
        k_dbl_changed = 0x0010,
        k_s8_changed  = 0x0020,
        k_u8_changed  = 0x0040,
        k_s16_changed = 0x0080,
        k_u16_changed = 0x0100,
        k_s32_changed = 0x0200,
        k_u32_changed = 0x0400,
        k_s64_changed = 0x0800,
        k_u64_changed = 0x1000
    };

    enum KeCharEncoding
    {
        k_utf8_changed  = 0x0001,
        k_utf32_changed = 0x0002,
        k_text_changed  = 0x0004
    };
}


void MainWindow::updateByteEncoding_(QByteArray ba, int changed)
{
    // 字节序列中，高位在前(begin)，低位在后(end)，即ba[0]表示最高位字节
    // 所以转换为数字时，须使用bigEndian
    // 当ba尺寸不足时，向前补0，即相当于高位补0
    // 当ba尺寸超差时，截取低位数据，即相当于从ba的尾部截取数据

    kPrivate::updating = true;

    if (!(changed & kPrivate::k_bin_changed)) {
        auto bin = QByteArrayUtil::toBin(ba);
        ui->bin->setText(bin);
    }

    if (!(changed & kPrivate::k_oct_changed)) {
        auto oct = QByteArrayUtil::toOct(ba);
        ui->oct->setText(oct);
    }

    if (!(changed & kPrivate::k_hex_changed)) {
        auto hex = ba.toHex();
        ui->hex->setText(hex);
    }

    if (!(changed & kPrivate::k_u8_changed)) {
        if (ba.size() == 0) {
            ui->u8->setText("");
        }
        else {
            auto u8 = qFromBigEndian<std::uint8_t>(ba.data() + ba.size() - 1); // 取最后1个字节
            ui->u8->setText(QString("%1").arg(u8));
        }
    }

    if (!(changed & kPrivate::k_s8_changed)) {
        if (ba.size() == 0) {
            ui->s8->setText("");
        }
        else {
            auto s8 = qFromBigEndian<std::int8_t>(ba.data() + ba.size() - 1); // 取最后1个字节
            ui->s8->setText(QString("%1").arg(s8));
        }
    }

    if (!(changed & kPrivate::k_u16_changed)) {
        if (ba.size() == 0) {
            ui->u16->setText("");
        }
        else {
            while (ba.size() < 2)
                ba.push_front(char(0));
            auto u16 = qFromBigEndian<std::uint16_t>(ba.data() + ba.size() - 2); // 取最后2个字节
            ui->u16->setText(QString("%1").arg(u16));
        }
    }

    if (!(changed & kPrivate::k_s16_changed)) {
        if (ba.size() == 0) {
            ui->s16->setText("");
        }
        else {
            while (ba.size() < 2)
                ba.push_front(char(0));
            auto s16 = qFromBigEndian<std::int16_t>(ba.data() + ba.size() - 2); // 取最后2个字节
            ui->s16->setText(QString("%1").arg(s16));
        }
    }

    if (!(changed & kPrivate::k_u32_changed)) {
        if (ba.size() == 0) {
            ui->u32->setText("");
        }
        else {
            while (ba.size() < 4)
                ba.push_front(char(0));
            auto u32 = qFromBigEndian<std::uint32_t>(ba.data() + ba.size() - 4); // 取最后4个字节
            ui->u32->setText(QString("%1").arg(u32));
        }
    }

    if (!(changed & kPrivate::k_s32_changed)) {
        if (ba.size() == 0) {
            ui->s32->setText("");
        }
        else {
            while (ba.size() < 4)
                ba.push_front(char(0));
            auto s32 = qFromBigEndian<std::int32_t>(ba.data() + ba.size() - 4); // 取最后4个字节
            ui->s32->setText(QString("%1").arg(s32));
        }
    }

    if (!(changed & kPrivate::k_u64_changed)) {
        if (ba.size() == 0) {
            ui->u64->setText("");
        }
        else {
            while (ba.size() < 8)
                ba.push_front(char(0));
            auto u64 = qFromBigEndian<std::uint64_t>(ba.data() + ba.size() - 8); // 取最后8个字节
            ui->u64->setText(QString("%1").arg(u64));
        }
    }

    if (!(changed & kPrivate::k_s64_changed)) {
        if (ba.size() == 0) {
            ui->s64->setText("");
        }
        else {
            while (ba.size() < 8)
                ba.push_front(char(0));
            auto s64 = qFromBigEndian<std::int64_t>(ba.data() + ba.size() - 8); // 取最后8个字节
            ui->s64->setText(QString("%1").arg(s64));
        }
    }

    if (!(changed & kPrivate::k_flt_changed)) {
        if (ba.size() == 0) {
            ui->flt->setText("");
        }
        else {
            while (ba.size() < sizeof(float))
                ba.push_front(char(0));
            auto flt = qFromBigEndian<float>(ba.data() + ba.size() - sizeof(float));
            ui->flt->setText(QString("%1").arg(flt));
        }
    }

    if (!(changed & kPrivate::k_dbl_changed)) {
        if (ba.size() == 0) {
            ui->dbl->setText("");
        }
        else {
            while (ba.size() < sizeof(double))
                ba.push_front(char(0));
            auto dbl = qFromBigEndian<double>(ba.data() + ba.size() - sizeof(double));
            ui->dbl->setText(QString("%1").arg(dbl));
        }
    }

    kPrivate::updating = false;
}


void MainWindow::updateCharEncoding_(const QString& text, int changed)
{
    kPrivate::updating = true;

    if (!(changed & kPrivate::k_utf8_changed)) {
        auto utf8 = text.toUtf8();
        ui->utf8->setText(utf8.toHex());
    }

    if (!(changed & kPrivate::k_utf32_changed)) {
        auto ucs4 = text.toUcs4();
        ui->utf32->setText(QByteArrayUtil::fromContainer(ucs4, true).toHex());
    }

    if (!(changed & kPrivate::k_text_changed)) {
        ui->text->setText(text);
    }

    kPrivate::updating = false;
}


void MainWindow::on_utf8_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    auto ba = QByteArrayUtil::fromHex(arg1.toLatin1());
    updateCharEncoding_(QString::fromUtf8(ba), kPrivate::k_utf8_changed);
}


void MainWindow::on_utf32_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    auto ba = QByteArrayUtil::fromHex(arg1.toLatin1());
    auto ucs4 = QByteArrayUtil::toContainer<QVector<char32_t>>(ba, true);
    updateCharEncoding_(QString::fromUcs4(ucs4.data(), ucs4.size()), kPrivate::k_utf32_changed);
}


void MainWindow::on_text_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    updateCharEncoding_(arg1, kPrivate::k_text_changed);
}


void MainWindow::on_hex_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    updateByteEncoding_(QByteArrayUtil::fromHex(arg1.toLatin1()), kPrivate::k_hex_changed);
}


void MainWindow::on_bin_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    updateByteEncoding_(QByteArrayUtil::fromBin(arg1.toLatin1()), kPrivate::k_bin_changed);
}


void MainWindow::on_oct_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    updateByteEncoding_(QByteArrayUtil::fromOct(arg1.toLatin1()), kPrivate::k_oct_changed);
}


void MainWindow::on_s8_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<std::int8_t>(arg1.toInt());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_s8_changed);
}


void MainWindow::on_u8_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<std::uint8_t>(arg1.toUInt());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_u8_changed);
}


void MainWindow::on_s16_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<std::int16_t>(arg1.toInt());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_s16_changed);
}


void MainWindow::on_u16_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<std::uint16_t>(arg1.toUInt());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_u16_changed);
}


void MainWindow::on_s32_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<std::int32_t>(arg1.toInt());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_s32_changed);
}


void MainWindow::on_u32_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<std::uint32_t>(arg1.toUInt());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_u32_changed);
}


void MainWindow::on_s64_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<std::int64_t>(arg1.toLongLong());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_s64_changed);
}


void MainWindow::on_u64_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<std::uint64_t>(arg1.toULongLong());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_u64_changed);
}


void MainWindow::on_flt_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<float>(arg1.toFloat());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_flt_changed);
}


void MainWindow::on_dbl_textChanged(const QString &arg1)
{
    if (kPrivate::updating) // 防重入
        return;

    QByteArray ba;
    if (arg1.length()) {
        auto val = qToBigEndian<double>(arg1.toDouble());
        ba = QByteArray::fromRawData((char*)&val, sizeof(val));
    }
    updateByteEncoding_(ba, kPrivate::k_dbl_changed);
}

